/**
 * go.js - библиотека, упрощающая некоторые действия в JavaScript
 *
 * @package go.js
 * @author  Григорьев Олег aka vasa_c
 * @link    http://code.google.com/p/go-js/
 * @version 0.2
 * @license MIT (http://www.opensource.org/licenses/mit-license.php)
 */
 
var go = (function(window, undefined) {

var go = {};

go.Class = (function() {

    var BaseProto = {
        '__construct': (function() {}),
        
        '__destruct': (function() {}),
        
        'destroy': (function() {
            if (this["$destroyed"]) {
                return false;
            }
            this.__destruct();
            this.__destroy_todestroy();
            this.__destroy_reset();
            this["$destroyed"] = true;
            return true;
        }),
        
        '__destroy_todestroy': (function() {
            var todestroy = this["$todestroy"];
            var len = todestroy.length;
            for (var i = 0; i < len; i++) {
                todestroy[i].destroy();
            }
        }),
        
        '__destroy_reset': (function() {
            var destroy = this.destroy;
            for (var name in this) {
                this[name] = null;
            }
            this.destroy = destroy;
        }),
        
        '__createObjectProperty': (function(name, value) {
            this[name] = value;
            this["$todestroy"].push(value);
            return value;            
        })
    };
    
    var EmptyConstructor = (function() {});
    
    function createProto(parentProto) {
        EmptyConstructor.prototype = parentProto;
        return (new EmptyConstructor());
    }

    function goClass(parent, props) {
    
        if (arguments.length == 1) {
            props  = parent;
            parent = null;
        }
        
        var parentProto = parent ? parent.$proto : BaseProto;
        var proto = createProto(parentProto);

        function Class() {
            if (this["$abstract"]) {
                throw "Cannot instantiate abstract class";
            }
            var binds = arguments.callee["$binds"];
            var _this = this;
            for (var name in binds) {
                this[name] = (function(func) {
                    var method = (function() {
                        return func.apply(_this, arguments);
                    });
                    method["$self"]    = func["$self"];
                    method["__parent"] = func["__parent"];
                    return method;
                })(binds[name]);
            }
            this["$destroyed"] = false;
            this["$todestroy"] = [];
            this.__construct.apply(this, arguments);            
        }
        var binds         = {}; 
        var statics       = {};        
        Class.prototype   = proto;
        Class["$proto"]   = proto;
        Class["$props"]   = props;
        Class["$parent"]  = parent;
        Class["$binds"]   = binds;
        Class["$statics"] = statics;        
        if (parent) {
            var parentBinds = parent["$binds"];
            for (var name in parentBinds) {
                binds[name] = parentBinds[name];
            }
            var parentStatics = parent["$statics"];
            for (var name in parentStatics) {
                statics[name] = parentStatics[name];
            }
        }             
        
        for (var name in props) {
            var prop  = props[name];
            var ismethod = (typeof(prop) == "function");
            var comps = name.split("_");
            if (comps.length > 1) {
                var postfix = comps.pop();               
                if (postfix == "static") {
                    name = comps.join("_");
                    statics[name] = prop;
                    if (ismethod) {
                        prop["$self"]    = Class;
                        prop["__parent"] = parent ? parent[name] : null;
                    }
                    continue;
                }
                if ((postfix == "bind") && (ismethod)) {
                    name = comps.join("_");                  
                    binds[name]      = prop;
                    prop["$self"]    = Class;
                    prop["__parent"] = parent ? parentBinds[name] : null;
                    continue;
                }
            }
            if (ismethod) {
                prop["$self"]   = Class;
                prop["__parent"] = parentProto[name];
            }
            proto[name] = prop;
        }        
        delete(proto["eoc"]);
        
        proto["$self"]   = Class;
        proto["$parent"] = parent;
        
        for (var name in statics) {
            Class[name] = statics[name];
        }

        return Class;    
    }
    
    return goClass;
})();

return go;
})(window);
